using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using PlaytimeSaveTypes;

using Keys = Microsoft.Xna.Framework.Input.Keys;

namespace BoneAnimationProt
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        OpenFileDialog openDiag;
        SaveFileDialog saveDiag;

        int addedJoints = 0;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        JointAnimation anim;
        Texture2D emptyTexture, point, rotHandle;
        SpriteFont font;

        Joint draggedJoint;
        Joint selectedJoint;

        bool rotatedSelected = false;
        Vector2 rotStart;
        bool freeDragging = false;
        bool drawBones = true;
        bool displayHelp = false;
        bool autoKeyframing = false;

        bool animScreen = false;
        float animScreenTimer = 0;
        public string fileToLoad = "";

        UIScreen screen;
        UIScreen back;
        UIScreen startScreen;
        UITimeLine timeLine;
        UITreeView treeView;

        const int SCREEN_WIDTH = 765;
        const int SCREEN_HEIGHT = 587;

        public static Game1 Instance { get; private set; }

        public Game1()
        {
            Instance = this;
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            Components.Add(new InputHandler(this));
            graphics.PreferredBackBufferWidth = SCREEN_WIDTH;
            graphics.PreferredBackBufferHeight = SCREEN_HEIGHT;

            openDiag = new OpenFileDialog();
            openDiag.DefaultExt = ".char";
            openDiag.Filter = "Character Data | *.char";
            openDiag.Multiselect = false;
            openDiag.ShowHelp = false;

            saveDiag = new SaveFileDialog();
            saveDiag.DefaultExt = ".char";
            saveDiag.Filter = "Character Data | *.char";
            saveDiag.ShowHelp = false;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {

            ResetAnim();
            
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            emptyTexture = Content.Load<Texture2D>("empty");
            point = Content.Load<Texture2D>("point");
            rotHandle = Content.Load<Texture2D>("rotHandle");
            font = Content.Load<SpriteFont>("font");
            IsMouseVisible = true;

            startScreen = new UIScreen();

            UIButton LoadBt = new UIButton();
            LoadBt.Parent = startScreen;
            LoadBt.textureDown = Content.Load<Texture2D>("btLoad");
            LoadBt.textureUp = LoadBt.textureDown;
            LoadBt.ButtonPressed += OnOpenDown;
            LoadBt.RelativePosition = new Vector2(SCREEN_WIDTH, SCREEN_HEIGHT) / 2 - new Vector2(LoadBt.textureDown.Width/2, 0);

            UIButton NewBt = new UIButton();
            NewBt.Parent = startScreen;
            NewBt.textureDown = Content.Load<Texture2D>("btNew");
            NewBt.textureUp = NewBt.textureDown;
            NewBt.RelativePosition = new Vector2(SCREEN_WIDTH, SCREEN_HEIGHT) / 2 - new Vector2(NewBt.textureDown.Width / 2, - 50);
            NewBt.ButtonPressed += OnNewDown; 
            startScreen.Childs.Add(LoadBt);
            startScreen.Childs.Add(NewBt);
            
            #region AnimScreenInit
            back = new UIScreen();
            back.background = Content.Load<Texture2D>("grid");

            screen = new UIScreen();
            screen.Parent = back;
            screen.background = Content.Load<Texture2D>("backPanel");
            screen.RelativePosition = new Vector2(SCREEN_WIDTH / 2 - screen.background.Width / 2, SCREEN_HEIGHT - screen.background.Height);

            UIButton sbutton = new UIButton();
            sbutton.Parent = screen;
            sbutton.RelativePosition = new Vector2(174, 43);
            sbutton.textureUp = Content.Load<Texture2D>("stopUP");
            sbutton.textureDown = Content.Load<Texture2D>("stopDOWN");
            sbutton.ButtonPressed += OnStopDown;

            UIButton pbutton = new UIButton();
            pbutton.Parent = screen;
            pbutton.RelativePosition = new Vector2(132, 43);
            pbutton.textureUp = Content.Load<Texture2D>("pauseUP");
            pbutton.textureDown = Content.Load<Texture2D>("pauseDOWN");
            pbutton.ButtonPressed += OnPauseDown;

            UIButton ppbutton = new UIButton();
            ppbutton.Parent = screen;
            ppbutton.RelativePosition = new Vector2(90, 43);
            ppbutton.textureUp = Content.Load<Texture2D>("playUP");
            ppbutton.textureDown = Content.Load<Texture2D>("playDOWN");
            ppbutton.ButtonPressed += OnPlayDown;

            UIButton nextBut = new UIButton();
            nextBut.Parent = screen;
            nextBut.RelativePosition = new Vector2(239, 69);
            nextBut.textureUp = Content.Load<Texture2D>("arrowRight");
            nextBut.textureDown = Content.Load<Texture2D>("arrowRight");
            nextBut.ButtonPressed += OnNextDown;

            UIButton prevBut = new UIButton();
            prevBut.Parent = screen;
            prevBut.RelativePosition = new Vector2(219, 69);
            prevBut.textureUp = Content.Load<Texture2D>("arrowLeft");
            prevBut.textureDown = Content.Load<Texture2D>("arrowLeft");
            prevBut.ButtonPressed += OnPrevDown;

            UIButton addKeyBut = new UIButton();
            addKeyBut.Parent = screen;
            addKeyBut.RelativePosition = new Vector2(263, 44);
            addKeyBut.textureUp = Content.Load<Texture2D>("plus");
            addKeyBut.textureDown = Content.Load<Texture2D>("plus");
            addKeyBut.ButtonPressed += OnAddKeyDown;

            UIButton delKeyBut = new UIButton();
            delKeyBut.Parent = screen;
            delKeyBut.RelativePosition = new Vector2(313, 44);
            delKeyBut.textureUp = Content.Load<Texture2D>("minus");
            delKeyBut.textureDown = Content.Load<Texture2D>("minus");
            delKeyBut.ButtonPressed += OnDelKeyDown;

            UIButton plusTimeBut = new UIButton();
            plusTimeBut.Parent = screen;
            plusTimeBut.RelativePosition = new Vector2(660, 41);
            plusTimeBut.textureUp = Content.Load<Texture2D>("addTime");
            plusTimeBut.textureDown = Content.Load<Texture2D>("addTime");
            plusTimeBut.ButtonPressed += OnPlusTimeDown;

            UIButton minusTimeBut = new UIButton();
            minusTimeBut.Parent = screen;
            minusTimeBut.RelativePosition = new Vector2(660, 52);
            minusTimeBut.textureUp = Content.Load<Texture2D>("removeTime");
            minusTimeBut.textureDown = Content.Load<Texture2D>("removeTime");
            minusTimeBut.ButtonPressed += OnMinusTimeDown;

            UIToggleButton recordBut = new UIToggleButton();
            recordBut.Parent = screen;
            recordBut.RelativePosition = new Vector2(365, 43);
            recordBut.textureUp = Content.Load<Texture2D>("record");
            recordBut.textureDown = Content.Load<Texture2D>("record");
            recordBut.ButtonPressed += OnRecordDown;

            timeLine = new UITimeLine();
            timeLine.Parent = screen;
            timeLine.RelativePosition = new Vector2(264, 67);
            timeLine.startValue = 0;
            timeLine.endValue = anim.animationLength;
            timeLine.markerPos = 0;
            timeLine.markerTexture = Content.Load<Texture2D>("markerTex");
            timeLine.Size = new Vector2(467, 25);
            timeLine.OnMouseDown += OnTimelineClicked;

            treeView = new UITreeView(anim, Content.Load<SpriteFont>("font"));
            treeView.RelativePosition = new Vector2(600, -400);
            treeView.Parent = screen;

            UIButton AnimLoadBt = new UIButton();
            AnimLoadBt.Parent = screen;
            AnimLoadBt.textureDown = Content.Load<Texture2D>("btLoad");
            AnimLoadBt.textureUp = AnimLoadBt.textureDown;
            AnimLoadBt.ButtonPressed += OnOpenDown;
            AnimLoadBt.RelativePosition = new Vector2(11, 9);

            UIButton AnimNewBt = new UIButton();
            AnimNewBt.Parent = screen;
            AnimNewBt.textureDown = Content.Load<Texture2D>("btNew");
            AnimNewBt.textureUp = AnimNewBt.textureDown;
            AnimNewBt.RelativePosition = new Vector2(11, 32);
            AnimNewBt.ButtonPressed += OnNewDown;

            UIButton AnimSaveBt = new UIButton();
            AnimSaveBt.Parent = screen;
            AnimSaveBt.textureDown = Content.Load<Texture2D>("btSave");
            AnimSaveBt.textureUp = AnimSaveBt.textureDown;
            AnimSaveBt.RelativePosition = new Vector2(11, 56);
            AnimSaveBt.ButtonPressed += OnSaveDown; 

            screen.Childs.Add(treeView);
            screen.Childs.Add(sbutton);
            screen.Childs.Add(pbutton);
            screen.Childs.Add(ppbutton);
            screen.Childs.Add(nextBut);
            screen.Childs.Add(prevBut);
            screen.Childs.Add(addKeyBut);
            screen.Childs.Add(delKeyBut);
            screen.Childs.Add(timeLine);
            screen.Childs.Add(plusTimeBut);
            screen.Childs.Add(minusTimeBut);
            screen.Childs.Add(recordBut);
            screen.Childs.Add(AnimLoadBt);
            screen.Childs.Add(AnimNewBt);
            screen.Childs.Add(AnimSaveBt);
            back.RelativePosition = new Vector2(0, -SCREEN_HEIGHT);
            #endregion

            if (fileToLoad != "")
            {
                LoadAnim(fileToLoad);
            }
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            #region AnimScreen
            if (animScreen)
            {
                animScreenTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
                anim.Update(gameTime);

                if (InputHandler.KeyPressed(Keys.D1))
                    anim.Play();

                if (InputHandler.KeyPressed(Keys.D2))
                    anim.Pause();

                if (InputHandler.KeyPressed(Keys.D3))
                    anim.Stop();

                if (InputHandler.KeyPressed(Keys.OemPlus))
                    anim.animationSpeed = (float)Math.Round(anim.animationSpeed + 0.2f, 4);

                if (InputHandler.KeyPressed(Keys.OemMinus))
                {
                    if (anim.animationSpeed > 0.2f)
                        anim.animationSpeed = (float)Math.Round(anim.animationSpeed - 0.2f, 4);
                }

                if (InputHandler.KeyPressed(Keys.Right))
                    anim.NextKeyframe();

                if (InputHandler.KeyPressed(Keys.Left))
                    anim.PreviousKeyframe();

                if (InputHandler.KeyPressed(Keys.Tab))
                    drawBones = !drawBones;

                if (InputHandler.KeyPressed(Keys.F1))
                    displayHelp = !displayHelp;

                if (InputHandler.KeyPressed(Keys.Up))
                    anim.JumpTo((float)Math.Round(anim.animationTimer + anim.animationLength / 10, 4));

                if (InputHandler.KeyPressed(Keys.Down))
                    anim.JumpTo((float)Math.Round(anim.animationTimer - anim.animationLength / 10, 4));

                if (InputHandler.RightMouseDown())
                {
                    Joint parentJoint = null;
                    foreach (Joint joint in anim.joints)
                    {
                        Vector2 distance = InputHandler.MousePosition - joint.GetAbsoluteTranslation();
                        if (distance.Length() < 10)
                        {
                            parentJoint = joint;
                            break;
                        }
                    }
                    if (parentJoint != null)
                    {
                        Joint newJoint = new Joint(parentJoint.Name + addedJoints.ToString(), 0, Vector2.Zero, parentJoint);
                        anim.AddJoint(newJoint);
                        addedJoints++;
                        draggedJoint = newJoint;
                        freeDragging = true;
                    }
                }
                else if (InputHandler.LeftMouseDown())
                {
                    float closestDist = float.MaxValue;
                    Joint closestJoint = null;
                    foreach (Joint joint in anim.joints)
                    {
                        Vector2 distance = InputHandler.MousePosition - joint.GetAbsoluteTranslation();

                        if (distance.Length() < closestDist)
                        {
                            closestDist = distance.Length();
                            closestJoint = joint;
                        }                        
                    }

                    if (closestDist < 25)
                    {
                        selectedJoint = closestJoint;
                        if (InputHandler.KeyDown(Keys.LeftShift))
                        {
                            if (selectedJoint == closestJoint)
                                draggedJoint = closestJoint;
                        }
                        else
                        {
                            rotatedSelected = true;
                            rotStart = InputHandler.MousePosition;
                        }
                    }
                }
                else if (InputHandler.LeftMouseUp() || InputHandler.RightMouseUp())
                {
                    draggedJoint = null;
                    freeDragging = false;
                    rotatedSelected = false;
                }

                if (selectedJoint != null && selectedJoint.parent != null && rotatedSelected)
                {
                    int dir = -1;
                    if(IsCW(selectedJoint.parent.GetAbsoluteTranslation(), rotStart, InputHandler.MousePosition))
                        dir = 1;

                    Vector2 dir1 = rotStart - selectedJoint.parent.GetAbsoluteTranslation();
                    dir1.Normalize();
                    Vector2 dir2 = InputHandler.MousePosition - selectedJoint.parent.GetAbsoluteTranslation();
                    dir2.Normalize();

                    float newAngle = dir * (float)Math.Acos(Vector2.Dot(dir1, dir2));
                    if (!float.IsNaN(newAngle))
                        selectedJoint.relativeRotation = newAngle;
                }
                else if (draggedJoint != null)
                {
                    if (freeDragging || InputHandler.KeyDown(Keys.LeftShift))
                    {
                        foreach (Joint child in draggedJoint.Childs)
                        {
                            int dir = -1;
                            if (IsCW(child.parent.GetAbsoluteTranslation(), rotStart, InputHandler.MousePosition))
                                dir = 1;

                            Vector2 dir1 = rotStart - child.parent.GetAbsoluteTranslation();
                            dir1.Normalize();
                            Vector2 dir2 = InputHandler.MousePosition - child.parent.GetAbsoluteTranslation();
                            dir2.Normalize();

                            float newAngle = dir * (float)Math.Acos(Vector2.Dot(dir1, dir2));
                            if (!float.IsNaN(newAngle))
                                child.relativeRotation = newAngle;
                        }
                    }
                    OnAddKeyDown(null, null);
                }

                if (InputHandler.KeyPressed(Keys.I))
                {
                    OnAddKeyDown(null, null);
                }


                if (back.RelativePosition.Y < 0)
                    back.RelativePosition.Y = InterpolateCrazy(animScreenTimer, 0, SCREEN_HEIGHT, 1.5f) - SCREEN_HEIGHT;
                else
                    back.RelativePosition.Y = 0;

                screen.Update(gameTime);
                timeLine.markerPos = anim.animationTimer;
            }
            #endregion
            else
                startScreen.Update(gameTime);
            base.Update(gameTime);
        }

        public static bool IsCW(Vector2 _v1, Vector2 _v2, Vector2 _v3)
        {
            return (_v1.X * _v2.Y + _v2.X * _v3.Y + _v3.X * _v1.Y -
                    _v2.Y * _v3.X - _v3.Y * _v1.X - _v1.Y * _v2.X) > 0;
        }

        public float InterpolateCrazy(float t, float b, float c, float d)
        {
            if ((t /= d) < (1 / 2.75))
            {
                return c * (7.5625f * t * t) + b;
            }
            else if (t < (2 / 2.75))
            {
                return c * (7.5625f * (t -= (1.5f / 2.75f)) * t + .75f) + b;
            }
            else if (t < (2.5 / 2.75))
            {
                return c * (7.5625f * (t -= (2.25f / 2.75f)) * t + .9375f) + b;
            }
            else
            {
                return c * (7.5625f * (t -= (2.625f / 2.75f)) * t + .984375f) + b;
            }
        }

        public void ResetAnim()
        {
            
                anim = new JointAnimation(1);
                // TODO: Add your initialization logic here

                anim.AddJoint(new Joint("Base", 0, new Vector2(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2), null));
                anim.AddJoint(new Joint("Body", 0, new Vector2(0, 50), anim.joints[0]));
                anim.joints[1].sprite = new Sprite("body", Content.Load<Texture2D>("body"), SpriteEffects.None, new Vector2(0, 10), 0, 0.9f);

                anim.AddJoint(new Joint("hipR", 0, new Vector2(-11, 5), anim.joints[1]));
                anim.AddJoint(new Joint("hipL", 0, new Vector2(15, 5), anim.joints[1]));

                anim.AddJoint(new Joint("upperLegR", 0, new Vector2(-4, 16), anim.joints[2]));
                anim.joints[4].sprite = new Sprite("upperLeg", Content.Load<Texture2D>("upperLeg"), SpriteEffects.None, new Vector2(0, 5), 0, 0.95f);
                anim.AddJoint(new Joint("upperLegL", 0, new Vector2(4, 16), anim.joints[3]));
                anim.joints[5].sprite = new Sprite("upperLeg", Content.Load<Texture2D>("upperLeg"), SpriteEffects.None, new Vector2(0, 5), 0, 0.75f);

                anim.AddJoint(new Joint("head", 0, new Vector2(0, -30), anim.joints[0]));
                anim.joints[6].sprite = new Sprite("head", Content.Load<Texture2D>("head"), SpriteEffects.None, new Vector2(100, 100), (float)Math.PI, 0.6f);

                anim.AddJoint(new Joint("shoulderL", 0, new Vector2(20, 10), anim.joints[0]));
                anim.AddJoint(new Joint("shoulderR", 0, new Vector2(-10, 5), anim.joints[0]));

                anim.AddJoint(new Joint("upperArmL", 0, new Vector2(27, 13), anim.joints[7]));
                anim.joints[9].sprite = new Sprite("upperArm", Content.Load<Texture2D>("upperArm"), SpriteEffects.None, new Vector2(-5, 10), 0.16f, 0.7f);
                anim.AddJoint(new Joint("upperArmR", 0, new Vector2(-10, 25), anim.joints[8]));
                anim.joints[10].sprite = new Sprite("upperArm", Content.Load<Texture2D>("upperArm"), SpriteEffects.FlipHorizontally, new Vector2(5, 10), -0.2f, 0.95f);

                anim.AddJoint(new Joint("lowerArmL", 0, new Vector2(0, 30), anim.joints[9]));
                anim.joints[11].sprite = new Sprite("lowerArm", Content.Load<Texture2D>("lowerArm"), SpriteEffects.None, new Vector2(3, 5), 0, 0.6f);
                anim.AddJoint(new Joint("lowerArmR", 0, new Vector2(0, 30), anim.joints[10]));
                anim.joints[12].sprite = new Sprite("lowerArm", Content.Load<Texture2D>("lowerArm"), SpriteEffects.FlipHorizontally, new Vector2(-3, 5), 0, 0.95f);

                anim.AddJoint(new Joint("lowerLegR", 0, new Vector2(-5, 20), anim.joints[4]));
                anim.joints[13].sprite = new Sprite("lowerLeg", Content.Load<Texture2D>("lowerLeg"), SpriteEffects.None, new Vector2(0, 2), 0, 0.92f);
                anim.AddJoint(new Joint("lowerLegL", 0, new Vector2(5, 20), anim.joints[5]));
                anim.joints[14].sprite = new Sprite("lowerLeg", Content.Load<Texture2D>("lowerLeg"), SpriteEffects.None, new Vector2(0, 2), 0, 0.72f);
            
        }

        public void LoadAnim(string _file)
        {
            Stream fileName = File.Open(_file, FileMode.Open);

            XmlSerializer x = new XmlSerializer(typeof(JointAnimationSaveData));
            JointAnimationSaveData data = (JointAnimationSaveData)x.Deserialize(fileName);
            anim = new JointAnimation(data);
            animScreen = true;
            fileName.Close();

            foreach (float key in anim.keyframes.Keys)
                timeLine.additionalMarkers.Add(key);
        }

        #region Interface Handlers

        public void OnNewDown(UIElement _sender, object _message)
        {
            animScreen = true;
            animScreenTimer = 0;
            ResetAnim();
            timeLine.additionalMarkers.Clear();
        }

        public void OnSaveDown(UIElement _sender, object _message)
        {
            if (saveDiag.ShowDialog() == DialogResult.OK)
            {
                JointAnimationSaveData data = TypeBuilder.CreateAnimationSaveData(anim);
                XmlSerializer x = new XmlSerializer(data.GetType());
                Stream file = saveDiag.OpenFile();
                x.Serialize(file, data);
                file.Close();
                
            }
        }

        public void OnOpenDown(UIElement _sender, object _message)
        {
            if (  openDiag.ShowDialog() == DialogResult.OK)
            {
                Stream fileName = openDiag.OpenFile();
                
                XmlSerializer x = new XmlSerializer(typeof(JointAnimationSaveData));
                JointAnimationSaveData data = (JointAnimationSaveData)x.Deserialize(fileName);
                anim = new JointAnimation(data);
                animScreen = true;
                fileName.Close();

                foreach (float key in anim.keyframes.Keys)
                    timeLine.additionalMarkers.Add(key);
            }
        }

        public void OnRecordDown(UIElement _sender, object _message)
        {
            autoKeyframing = !autoKeyframing;
        }

        public void OnStopDown(UIElement _sender, object _message)
        {
            anim.Stop();
        }

        public void OnPauseDown(UIElement _sender, object _message)
        {
            anim.Pause();
        }

        public void OnPlayDown(UIElement _sender, object _message)
        {
            anim.Play();
        }

        public void OnNextDown(UIElement _sender, object _message)
        {
            anim.NextKeyframe();
        }

        public void OnPrevDown(UIElement _sender, object _message)
        {
            anim.PreviousKeyframe();
        }

        public void OnAddKeyDown(UIElement _sender, object _message)
        {
            anim.AddKeyFrame(anim.joints, anim.animationTimer);
            if (!timeLine.additionalMarkers.Contains(anim.animationTimer))
                timeLine.additionalMarkers.Add(anim.animationTimer);
        }

        public void OnDelKeyDown(UIElement _sender, object _message)
        {
            anim.DeleteKeyFrame(anim.animationTimer);
            timeLine.additionalMarkers.Remove(anim.animationTimer);
        }

        public void OnPlusTimeDown(UIElement _sender, object _message)
        {
            anim.JumpTo((float)Math.Round(anim.animationTimer + anim.animationLength / 10, 4));
        }

        public void OnMinusTimeDown(UIElement _sender, object _message)
        {
            anim.JumpTo((float)Math.Round(anim.animationTimer - anim.animationLength / 10, 4));
        }

        public void OnTimelineClicked(UIElement _sender, object _message)
        {
            anim.JumpTo((float)_message);
        }
        #endregion

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.BlanchedAlmond);
            spriteBatch.Begin();
            back.Draw(spriteBatch);
            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone, null);
            if(animScreen)
            {
                foreach (Joint joint in anim.joints)
                {
                    if (joint.parent != null)
                    {
                        if (!joint.sprite.HasValue)
                        {
                            if (drawBones)
                            {
                                Vector2 lineVector = joint.parent.GetAbsoluteTranslation() - joint.GetAbsoluteTranslation();
                                float angle = (float)Math.Atan2(lineVector.Y, lineVector.X);
                                float length = lineVector.Length();
                                Vector2 orthogonal = new Vector2(-lineVector.Y, lineVector.X);
                                orthogonal.Normalize();

                                Vector2 startPoint = joint.GetAbsoluteTranslation() - orthogonal * (3f / 2);

                                spriteBatch.Draw(emptyTexture, startPoint, null, Color.Black,
                                       angle, Vector2.Zero, new Vector2(length, 3),
                                       SpriteEffects.None, 0.5f);
                            }
                        }
                        else
                        {
                            Vector2 lineVector = joint.parent.GetAbsoluteTranslation() - joint.GetAbsoluteTranslation();
                            float angle = (float)Math.Atan2(lineVector.Y, lineVector.X) + (float)Math.PI / 2;
                            float length = lineVector.Length();
                            Vector2 orthogonal = new Vector2(-lineVector.Y, lineVector.X);
                            orthogonal.Normalize();

                            Vector2 startPoint = joint.parent.GetAbsoluteTranslation() - orthogonal * ((float)joint.sprite.Value.Texture.Width / 2);
                            spriteBatch.Draw(joint.sprite.Value.Texture, startPoint, null, Color.White,
                                   angle + joint.sprite.Value.rotOffset, joint.sprite.Value.Offset, Vector2.One,
                                   joint.sprite.Value.Effects, joint.sprite.Value.depth);
                        }

                    }
                    Color drawColor = Color.Orange;
                    if (joint.parent == null)
                        drawColor = Color.Red;
                    if (joint == selectedJoint)
                        drawColor = Color.Blue;
                    if (drawBones)
                    {
                        spriteBatch.Draw(point, joint.GetAbsoluteTranslation(), null, drawColor, joint.GetAbsoluteRotation(), new Vector2(5), 1f, SpriteEffects.None, 0);
                        if(joint == selectedJoint && InputHandler.KeyDown(Keys.LeftShift))
                            spriteBatch.Draw(rotHandle, joint.GetAbsoluteTranslation(), null, Color.Blue, joint.relativeRotation, new Vector2(12.5f), 1, SpriteEffects.None, 0);
                    }
                }

            }

            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
            if(animScreen)
            {
                if (displayHelp)
                {
                    spriteBatch.DrawString(font, anim.animationTimer.ToString() + "/" + anim.animationLength.ToString(), Vector2.Zero, Color.Black);
                    spriteBatch.DrawString(font, "Controls:", new Vector2(0, 20), Color.Black);
                    spriteBatch.DrawString(font, "1: Play", new Vector2(0, 40), Color.Black);
                    spriteBatch.DrawString(font, "2: Pause", new Vector2(0, 60), Color.Black);
                    spriteBatch.DrawString(font, "3: Stop", new Vector2(0, 80), Color.Black);

                    spriteBatch.DrawString(font, "I: Insert Keyframe", new Vector2(0, 120), Color.Black);
                    spriteBatch.DrawString(font, "Left: Previous Keyframe", new Vector2(0, 140), Color.Black);
                    spriteBatch.DrawString(font, "Right: Next Keyframe", new Vector2(0, 160), Color.Black);
                    spriteBatch.DrawString(font, "Up: +" + (anim.animationLength / 10).ToString() + " Animation Time", new Vector2(0, 180), Color.Black);
                    spriteBatch.DrawString(font, "Down: -" + (anim.animationLength / 10).ToString() + "Animation Time", new Vector2(0, 200), Color.Black);

                    spriteBatch.DrawString(font, "Leftclick + Drag: Move Point", new Vector2(0, 240), Color.Black);
                    spriteBatch.DrawString(font, "Rightclick + Drag: Add Point", new Vector2(0, 260), Color.Black);

                    spriteBatch.DrawString(font, "Playback Speed: " + anim.animationSpeed.ToString(), new Vector2(0, 290), Color.Black);
                }
                screen.Draw(spriteBatch);
            }
            else
                startScreen.Draw(spriteBatch);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
